package com.example.sbeducation.websocket;

import com.alibaba.fastjson.JSON;
import com.example.sbeducation.dto.ChatMessageDTO;
import com.example.sbeducation.service.ChatMessageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * WebSocket聊天端点
 */
@Slf4j
@Component
@ServerEndpoint("/ws/chat/{userId}")
public class ChatEndpoint {

  private static ChatMessageService chatMessageService;

  // 存储当前在线的WebSocket连接
  private static final Map<Long, Session> ONLINE_SESSIONS = new ConcurrentHashMap<>();

  @Autowired
  public void setChatMessageService(ChatMessageService chatMessageService) {
    ChatEndpoint.chatMessageService = chatMessageService;
  }

  /**
   * 连接建立成功调用的方法
   */
  @OnOpen
  public void onOpen(Session session, @PathParam("userId") Long userId) {
    ONLINE_SESSIONS.put(userId, session);
    log.info("用户{}加入聊天，当前在线人数：{}", userId, ONLINE_SESSIONS.size());
  }

  /**
   * 连接关闭调用的方法
   */
  @OnClose
  public void onClose(@PathParam("userId") Long userId) {
    ONLINE_SESSIONS.remove(userId);
    log.info("用户{}退出聊天，当前在线人数：{}", userId, ONLINE_SESSIONS.size());
  }

  /**
   * 收到客户端消息后调用的方法
   */
  @OnMessage
  public void onMessage(String message, @PathParam("userId") Long userId) {
    log.info("收到用户{}的消息：{}", userId, message);

    // 解析消息
    try {
      ChatMessageDTO chatMessageDTO = JSON.parseObject(message, ChatMessageDTO.class);
      chatMessageDTO.setSenderId(userId);

      // 保存消息到数据库
      Long messageId = chatMessageService.sendMessage(chatMessageDTO);

      // 如果接收者在线，立即推送消息
      if (ONLINE_SESSIONS.containsKey(chatMessageDTO.getReceiverId())) {
        Session receiverSession = ONLINE_SESSIONS.get(chatMessageDTO.getReceiverId());
        try {
          receiverSession.getBasicRemote().sendText(message);
        } catch (IOException e) {
          log.error("消息发送失败", e);
        }
      }
    } catch (Exception e) {
      log.error("消息处理失败", e);
    }
  }

  /**
   * 发生错误时调用
   */
  @OnError
  public void onError(Throwable error, @PathParam("userId") Long userId) {
    log.error("用户{}发生错误", userId, error);
  }

  /**
   * 发送消息到指定用户
   */
  public static void sendMessage(Long userId, String message) {
    Session session = ONLINE_SESSIONS.get(userId);
    if (session != null) {
      try {
        session.getBasicRemote().sendText(message);
      } catch (IOException e) {
        log.error("消息发送失败", e);
      }
    }
  }
}